/**
 * @file CECContext.hpp Deklarácia triedy CECContext.
 *
 * @author Martin Kosorinský.
 * @date 1.4.2009.
 */

#ifndef CECCONTEXT_HEADER
#define CECCONTEXT_HEADER

#include "miraclExtensions.hpp"

/**
 * @brief Veľkosť pomocného bufferu obsahujúceho vopred alokované štruktúry big.
 * @see CECContext::bigBuffer[].
 */
#ifndef BIG_BUFFER_SIZE
#define BIG_BUFFER_SIZE     3
#endif

/**
 * @brief Trieda predstavujúca kontext výpočtu diskrétneho logaritmu nad eliptickou krivkou.
 * Trieda CECContext je statická. Zapúzdruje globálne parametre výpočtu, akými sú
 * parametre eliptickej krivky, jej generátor a bod, ktorého diskrétny logaritmus hľadáme.
 * Dôležitou súčasťou triedy CECContext je procedúra CECContext::init, ktorá zabezpečuje inicializáciu
 * parametrov krivky, ako aj knižnice miracl. Dealokácia a deinicializácia je možná za
 * pomoci procedúry CECContext::free.
 */
class CECContext {
protected:
    /**
     * @brief Parameter A rovnice eliptickej krivky.
     */
    static big ecA;
    /**
     * @brief Parameter B rovnice eliptickej krivky.
     */
    static big ecB;
    /**
     * @brief Prvočíselný modul eliptickej krivky.
     */
    static big ecP;
    /**
     * @brief Rád grupy bodov eliptickej krivky.
     */
    static big ord;
    /**
     * @brief Prvok (väčšinou generátor) grupy, vzhľadom na ktorý hľadáme diskrétny logaritmus.
     */
    static epoint * G;
    /**
     * @brief Bod eliptickej krivky, ktorého diskrétny logaritmus hľadáme.
     */
    static epoint * H;
    /**
     * @brief Pomocný buffer staticky alokovaných štruktúr big.
     * Hlavným cieľom je eliminovať zbytočné alokácie a dealokácie premenných typu big
     * v kritických procedúrach, kde by opakovaná alokácia a dealokácia mohla spôsobiť
     * výraznejšie zníženie efektivity výpočtu. Veľkosť pola je možné určiť len počas kompilácie
     * nastavením BIG_BUFFER_SIZE.
     * @warning Treba využívať so zvýšenou opatrnosťou, môže spôsobiť ťažko odhaliteľné chyby.
     * @see BIG_BUFFER_SIZE.
     */
    static big bigBuffer[BIG_BUFFER_SIZE];
    /**
     * @brief Neverejný konštruktor (len aby nebolo možné triedu inštanciovať)
     */
    CECContext() {};
public:
    /**
     * @brief Inicializátor kontextu výpočtu diskrétneho logaritmu.
     * Procedúra zabezpečuje alokáciu a inicializáciu statických parametrov krivky a inicializáciu knižnice
     * miracl. Údaje o krivke a samotnom výpočte sú načítané z textového súboru, ktorého úplná
     * cesta je vstupným parametrom procedúry. V knižnici miracl je nastavená presnosť premenných typu big, ako
     * aj parametre eliptickej krivky, nad ktorou budu vykonávané výpočty.
     * Počas inicializácie nedochádza k overovaniu správnosti vstupov, čo môže spôsobiť chyby knižnice
     * miracl počas výpočtu.
     * Format vstupu z ecSource:<br>
     * - Bitová veľkosť prvočíselného modulu v desiatkovej sústave.
     * - Prvočíselný modul krivky v hexadecimálnom tvare.
     * - Krivkový parameter A v hexadecimálnom tvare.
     * - Parameter krivky B v hexadecimálnom tvare.
     * - Rád grupy bodov eliptickej krivky v hexadecimálnom tvare.
     * - X-ová súradnica generátora grupy v hexadecimálnom tvare.
     * - Y-ová súradnica generátora grupy v hexadecimálnom tvare.
     *
     * Bod, ktorého diskrétny logaritmus počítame je nastavený náhodne na základe údajov o krivke.
     * @warning Inicializácia musí prebehnúť pred začatím výpočtu, ale aj pred alokáciou prostriedkov knižnice
     * miracl.
     * @see free().
     * @param[in] ecSource je vstupný dátový stream obsahujúci parametre eliptickej krivky.
     * @param[in] mrPointRep je kód želanej reprezentácie bodov eliptickej krivky. Prípustné sú hodnoty
     * MR_PROJECTIVE a MR_AFFINE, predstavujúce parameter funkcie evurve_init(). Predvolená hodnota je MR_AFFINE.
     * @param[in] mrPrecision definuje presnosť knižnice miracl (prvý parameter funkcie mirsys). Predvolená
     * hodnota je 10.
     */
    static void init(std::istream &ecSource, int mrPointRep = MR_AFFINE, int mrPrecision = 10);
    /**
     * @brief Priamy inicializátor kontextu výpočtu diskrétneho logaritmu.
     * @copydetails CECContext::init()
     * @param[in] a Obsahuje prvý koeficient eliptickej krivky.
     * @param[in] b Obsahuje druhý koeficient eliptickej krivky.
     * @param[in] p Obsahuje modul eliptickej krivky.
     * @param[in] o Obsahuje rád eliptickej krivky.
     * @param[in] x Obsahuje prvú súradnicu generátora eliptickej krivky.
     * @param[in] y Obsahuje druhú súradnicu generátora eliptickej krivky.
     * @warning Procedúra predpokladá inicializovanú knižnicu MIRACL, to znamená, že pred volaním tejto inicializačnej
     * proced[ry musí byť volaná funkcia mirsys s príslušnými parametrami.
     */
    static void init(big a, big b, big p, big o, big x, big y, int mrPointRep = MR_AFFINE);
    /**
     * @brief Inicializátor (rozšírený) kontextu výpočtu diskrétneho logaritmu.
     * @copydetails CECContext::init()
     * @param[in] dlSource je vstupný dátový stream obsahujúci súradnice bodu, ktorého diskrétny
     * logaritmus hľadáme. Stream musí obsahovať X-ovú a Y-ovú súradnicu bodu v hexadecimálnom tvare,
     * oddelené bielym znakom.
     */
    static void init(std::istream &ecSource, std::istream &dlSource, int mrPointRep = MR_AFFINE, int mrPrecision = 10);
    /**
     * @brief Procedúra načíta parametre krivky z @c ecs súboru (formát knižnice  miracl).
     * @param[in] ecSource je vstupný dátový stream obsahujúci parametre eliptickej krivky.
     * @param[out] a Vopred alokovaná štruktúra, do ktorej bude uložený načítaný parameter A.
     * @param[out] b Vopred alokovaná štruktúra, do ktorej bude uložený načítaný parameter B.
     * @param[out] p Vopred alokovaná štruktúra, do ktorej bude uložený načítaný prvočíselný modul p.
     * @param[out] o Vopred alokovaná štruktúra, do ktorej bude uložený načítaný rád krivky.
     * @param[out] x Vopred alokovaná štruktúra, do ktorej bude uložená prvá súradnica generátora krivky.
     * @param[out] y Vopred alokovaná štruktúra, do ktorej bude uložená druhá súradnica generátora krivky.
     * @return Návratová hodnota je bitový rozsah prvočíselného modulu krivky (parametru p).
     */
    static int loadEcsFile(std::istream &ecSource, big a, big b, big p, big o, big x, big y);
    /**
     * @brief Procedúra pre prístup k inicializovaným parametrom krivky.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @param[out] a Vopred alokovaná štruktúra, do ktorej bude uložený načítaný parameter A.
     * @param[out] b Vopred alokovaná štruktúra, do ktorej bude uložený načítaný parameter B.
     * @param[out] p Vopred alokovaná štruktúra, do ktorej bude uložený načítaný prvočíselný modul p.
     * @param[out] o Vopred alokovaná štruktúra, do ktorej bude uložený načítaný rád krivky.
     * @param[out] g Smerník na alokovanú štruktúru bodu eliptickej krivky, do ktorej bude uložený inicializovaný generátor.
     */
    static void getParams(big a, big b, big p, big o, epoint * g);
    /**
     * @brief Procedúra zabezpečujúca dealokáciu kontextu.
     * Zabezpečí dealokáciu alokovaných prostriedkov ako aj deinicializáciu knižnice miracl.
     * @see init().
     */
    static void free();
    /**
     * @brief Inicializátor bodu, ktorého diskrétny logaritmus hľadáme.
     * Procedúra zabezpečí nastavenie bodu podľa súradníc dodaných ako parametre. Procedúra
     * nezabezpečuje alokáciu pamäti, len samotné nastavenie súradníc bodu.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @see setPoint(const epoint *)
     * @param[in] x Prvá súradnica bodu na eliptickej krivke.
     * @param[in] y Druhá súradnica bodu na eliptickej krivke, ktorého budeme hľadať.
     */
    static void setPoint(const big x, const big y);
    /**
     * @brief Inicializátor bodu, ktorého diskrétny logaritmus hľadáme.
     * Procedúra zabezpečí nastavenie bodu ako kópiu parametra @a P. Procedúra
     * nezabezpečuje alokáciu pamäti, len samotné nastavenie súradníc bodu.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @see setPoint(const big x,const big y)
     * @param[in] P Bod na eliptickej krivke, ktorého DL chceme hľadáme. Ak P == NULL, tak bude bod
     * vytvorený náhodne z inicializovanej grupy.
     */
    static void setPoint(const epoint * P = NULL);
    /**
     * @brief Inicializátor bodu, ktorého diskrétny logaritmus hľadáme.
     * Procedúra zabezpečí nastavenie bodu podľa jeho indexu. Procedúra
     * nezabezpečuje alokáciu pamäti, len samotné nastavenie súradníc bodu.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @see setPoint(const epoint *)
     * @param[in] n Index hľadaného bodu vzhľadom na inicializovaný generátor.
     */
    static void setPoint(const big n);
    /**
     * @brief Procedúra pre prístup k bodu, ktorého diskrétny logaritmus hľadáme.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @param[out] P Bod, do ktorého bude uložená kópia bodu #H.
     */
    static void getPoint(epoint * P);
    /**
     * @brief Procedúra pre prístup ku generátoru krivky.
     * @warning Pred volaním procedúry musí byt inicializovaný kontext výpočtu pomocou procedúru init().
     * @param[out] P Bod, do ktorého bude uložená kópia bodu #G.
     */
    static void getGenerator(epoint * P);
    /**
     * @brief Funkcia detegujúca stav inicializácie kontextu.
     * Boolovská funkcia, ktorej výstupom je hodnota TRUE ak bol kontext korektne inicializovaný.
     * V opačnom prípade je návratová hodnota FALSE.
     * Flag je nastavený na TRUE až po tom, ako sú úspešne inicializované všetky časti. Je tak možné,
     * že bude kontext inicializovaný len čiastočne, čo je signalizované hodnotou FALSE.
     * @see init()
     * @see free()
     * @return Návratová hodnota je TRUE, ak bol kontext korektne inicializovaný. V opačnom prípade vráti FALSE.
     */
    static bool isInitialized() {
        return initialized;
    };
private:
    /**
     * @brief Flag stavu inicializácie.
     */
    static bool initialized;
};

#endif /* CECCONTEXT_HEADER */

